'''游戏元素模块'''
import pygame
import random
#定义全局变量
SCREEN_RECT=pygame.Rect(0,0,480,700)                #game window
FRAME_INTERVAL=10                                   #逐帧动画间隔帧数

HERO_BOMB_COUNT=3                                   #英雄默认炸弹数量

HERO_DEFAULT_MID_BOTTOM=(SCREEN_RECT.centerx,       #英雄默认初始位置
                         SCREEN_RECT.bottom-90)

HERO_DEAD_EVENT=pygame.USEREVENT                    #英雄牺牲事件
HERO_POWER_OFF_EVENT=pygame.USEREVENT+1             #取消英雄无敌事件
HERO_FIRE_EVENT=pygame.USEREVENT+2                  #英雄发射子弹事件
THOW_SUPPLY_EVENT=pygame.USEREVENT+3                #投放道具事件
BULLET_ENHANCED_OFF_EVENT=pygame.USEREVENT+4        #关闭子弹增强时间


class GameSprite(pygame.sprite.Sprite):

    res_path ="./images/"

    def __init__(self,image_name,speed,*group):
        """初始化精灵对象"""
        #调用父类方法，把当前精灵对象放到精灵组里
        super(GameSprite,self).__init__(*group)

        #创建图片
        self.image=pygame.image.load(self.res_path+image_name)

        #获取矩形
        self.rect=self.image.get_rect()

        #设置移动速度
        self.speed=speed

        #
        self.mask=pygame.mask.from_surface(self.image)
    def update(self, *args):
        """更新元素数据"""
        self.rect.y+=self.speed

class Background(GameSprite):
    
    def __init__(self,is_out,*group):
        
        super(Background, self).__init__('background.png',0.75,*group)

        if is_out:
            self.rect.y = -self.rect.h

    def update(self, *args):
        super(Background, self).update(*args)

        #如果图片已经滚到底部，则立即回到窗口的最上面，供重新显示
        if self.rect.y > self.rect.h:
            self.rect.y = -self.rect.y


class StatusButton(GameSprite):
    """背景图片类"""
    def __init__(self,image_names,*groups):
        """image_names 接收一个元组，元组的0下标必须是暂停的图片，1下标必须是运行的图片"""
        super(StatusButton, self).__init__(image_names[0],0,*groups)

        # 准备用于切换显示的两张图片
        self.images=[pygame.image.load(self.res_path+name) for name in image_names]

    def switch_statrs(self,is_pause):
        """根据是否暂停，切换要使用的图片对象"""
        self.image = self.images[1 if is_pause else 0]

class Label(pygame.sprite.Sprite):
    """标签精灵类"""
    font_path= 'font/font.ttc'

    def __init__(self,text,size,color,*group):
        """初始化标签精灵的数据"""
        super(Label, self).__init__(*group)

        # 创建字体对象
        self.font = pygame.font.Font(self.font_path,size)

        # 字体颜色
        self.color=color

        # 精灵属性
        self.image = self.font.render(text,True,self.color)
        self.rect = self.image.get_rect()

    def set_text(self,text):
        """更新显示的文本内容"""
        self.image = self.font.render(text,True,self.color)
        self.rect = self.image.get_rect()




class Plane(GameSprite):
    """飞机精灵类"""
    def __init__(self,normal_names,speed,hp,value,wav_name,hurt_name,destroy_name,*groups):
        """飞机类的初始化"""
        super(Plane, self).__init__(normal_names[0],speed,*groups)

        # 飞机基本属性
        self.hp=hp              #当前生命值
        self.max_hp=hp          #初始生命值
        self.value=value        #分值
        self.wav_name=wav_name  #音效名

        #飞机要显示的图片
        self.normal_images=[pygame.image.load(self.res_path+name)for name in normal_names]  #正常图像列表
        self.normal_index=0   #正常状态图像索引
        self.hurt_image = pygame.image.load(self.res_path+hurt_name)   # 受伤图像
        self.destroy_images=[pygame.image.load(self.res_path+name) for name in destroy_name]#摧毁状态图像列表
        self.destroy_index=0  # 摧毁状态索引


    def reset_plane(self):
        """chongzhi"""
        self.hp=self.max_hp

        self.normal_index=0
        self.destroy_index=0

        self.image=self.normal_images[0]



    def update(self, *args):
        '''更新状态'''
        #判断是否要更新
        if not args[0]:
            return


        if self.hp==self.max_hp:
            #切换要显示的图片
            self.image = self.normal_images[self.normal_index]

            # 计算下一次显示的索引
            count=len(self.normal_images)
            self.normal_index= (self.normal_index + 1) % count

        elif self.hp>0:
            #受伤
            self.image=self.hurt_image

        else:
            #死亡
            if self.destroy_index<len(self.destroy_images):
                self.image=self.destroy_images[self.destroy_index]

                self.destroy_index+=1
            else:
                self.reset_plane()

class Enemy(Plane):
    """"""

    def __init__(self,kind,max_speed,*groups):
        """"""
        self.kind=kind
        self.max_speed=max_speed

        if kind ==0:
            #小敌机
            super(Enemy, self).__init__(
                ['enemy1.png'],1,1,1000,'enemy1_down.wav','enemy1.png',
                ['enemy1_down%d.png'%i for i in range(1,5)],
                *groups

            )
        elif kind ==1:
            #中敌机
            super(Enemy, self).__init__(
                ['enemy2.png'],1,6,6000,'enemy2_down.wav','enemy2_hit.png',
                ['enemy2_down%d.png'%i for i in range(1,5)],
                *groups

            )

        elif kind ==2:
            #大敌机
            super(Enemy, self).__init__(
                ['enemy3_n1.png','enemy3_n2.png'],1,15,15000,'enemy3_down.wav','enemy3_hit.png',
                ['enemy3_down%d.png'%i for i in range(1,7)],
                *groups

            )
        #初始化飞机时，要让飞机随机的选择一个位置显示
        self.reset_plane()

    def reset_plane(self):
        """重置敌人飞机"""
        super(Enemy, self).reset_plane()

        #敌人飞机的数据重置
        x =random.randint(0,SCREEN_RECT.w-self.rect.w)
        y =random.randint(0,SCREEN_RECT.h-self.rect.h) - SCREEN_RECT.h
        #
        self.rect.topleft=(x,y)
        #重置
        self.speed= random.randint(1,self.max_speed)

    def update(self, *args):
        """gengxing"""
        super(Enemy, self).update(*args)

        #判断
        if self.hp>0:
            self.rect.y += self.speed

        #外
        if self.rect.y>=SCREEN_RECT.h:
            self.reset_plane()


class Hero(Plane):
    """英雄飞机"""

    def __init__(self,*groups):
        """初始化英雄飞机"""
        self.is_power=False             #是否无敌
        self.bomb_count=HERO_BOMB_COUNT #炸弹数量
        self.bullets_kind=0             #子弹类型
        self.bullets_group=pygame.sprite.Group()    #子弹精灵组

        super(Hero, self).__init__(('me1.png','me2.png'),
                                   5,1,0,'me1_down.wav','me2.png',
                                   ['me_destroy_%d.png' % x for x in range(1,5)],
                                   *groups)
        self.rect.midbottom=HERO_DEFAULT_MID_BOTTOM         #创建外置：为屏幕底部中间

        pygame.time.set_timer(HERO_FIRE_EVENT,75)          #创建玩家飞机之后没隔0.2秒激活一次发射子弹事件

    def update(self, *args):
        """
        玩家飞机移动更新移动方法
        :param args:的0号小标说明了是否要更新下一帧动画，1号下标说明玩家飞机水平方向移动基数，2号下标说明玩家飞机垂直方向移动基数
        :return:
        """
        super(Hero, self).update(*args)

        if len(args)!=3 or self.hp<=0:
            return
        #pingmu weizhi
        self.rect.x+=args[1] * self.speed
        self.rect.x=0 if self.rect.x<0 else self.rect.x
        if self.rect.right>SCREEN_RECT.right:
            self.rect.right=SCREEN_RECT.right

        self.rect.y+=args[2] * self.speed
        self.rect.y= 0if self.rect.y<0 else self.rect.y
        if self.rect.bottom>SCREEN_RECT.bottom:
            self.rect.bottom=SCREEN_RECT.bottom

    def blow_up(self,enemies_group):
        """炸毁所有敌机，并返回得到的总分值"""
        #判断是否能够发起引爆
        if self.bomb_count<=0 or self.hp<=0:
            return 0
        #引爆所有敌机，累计得分
        self.bomb_count-=1
        score=0
        count = 0
        for enemy in enemies_group.sprites():
            if enemy.rect.bottom>0:
                score+=enemy.value
                enemy.hp=0
                count+=1

        return score



    def reset_plane(self):
        """重置玩家飞机数据"""
        super(Hero, self).reset_plane()

        self.is_power=True
        self.bomb_count=HERO_BOMB_COUNT
        self.bullets_kind=0

        #发布事件
        pygame.event.post(pygame.event.Event(HERO_DEAD_EVENT))

        #发布定时事件
        pygame.time.set_timer(HERO_POWER_OFF_EVENT,1000)

    def fire(self,display_group):
        """英雄飞机发射一轮新的子弹"""
        #zu
        groups=(display_group,self.bullets_group)

        #创建子弹并定位
        for i in range(2):
            bullet1=Bullet(self.bullets_kind,*groups)
            y=self.rect.y - i*15

            if self.bullets_kind==0:
                bullet1.rect.midbottom=(self.rect.centerx,y)

            else:
                bullet1.rect.midbottom=(self.rect.centerx-20,y)

                bullet2=Bullet(self.bullets_kind,*groups)
                bullet2.rect.midbottom=(self.rect.centerx+20,y)




class Bullet(GameSprite):
    """子弹类"""
    def __init__(self,kind,*group):
        """初始化子弹数据"""
        image_name="bullet1.png" if kind==0 else "bullet2.png"
        super(Bullet, self).__init__(image_name,-12,*group)
        self.damage=1         #杀伤力

    def update(self, *args):
        """更新子弹的数据"""
        super(Bullet, self).update(*args)

        # #飞出屏幕之外则需要销毁子弹
        # if self.rect.top==SCREEN_RECT.top:
        #     self.kill()

        if self.rect.x < 0 or self.rect.y <= 0:
            self.kill()
        # 可以在这里添加碰撞后的逻辑，比如停止移动、反弹等
        # 例如，让精灵停止在边缘：



class Supply(GameSprite):
    """道具精灵"""

    def  __init__(self,kind,*group):
        """初始化道具属性"""
        image_name='bomb_supply.png' if kind ==0 else 'bullet_supply.png'
        super(Supply, self).__init__(image_name,3,*group)

        self.kind =kind             #道具类型
        self.wav_name='get_bomb.wav' if kind==0 else'get_bullet.wav'    #道具音效

        self.rect.bottom=SCREEN_RECT.h #dao ju chu shi hua wei zhi
        
    def update(self, *args):
        """修改道具位置"""
        if self.rect.y>SCREEN_RECT.h:
            return        
            #如果已经移动到屏幕之外则不需要继续移动
        super(Supply, self).update(*args)

    def throw_supply(self):
        """投放道具"""
        self.rect.bottom=0     #移动道具到窗口的顶部
        self.rect.x=random.randint(0,SCREEN_RECT.w-self.rect.w)